Release 10.1A: OpenEdge Getting Started:
WebSpeed Essentials


Securing your WebSpeed application

Follow these rules to make sure that your application is as secure as possible.

Using DBAUTHKEY to lock your r-code to the database

An under-used feature of OpenEdge is the DBAUTHKEY (and RCODEKEY) features of PROUTIL.

With DBAUTHKEY, you assign a key to the database and then any code compiled against that database will have the key in it. When it comes time to run the code, if the key in the database does not match the key in the r-code, you will get an error similar to the following:

** CRC for table does not match CRC in program. Try recompiling. (1896) 

If you already have r-code deployed, use the RCODEKEY function of PROUTIL to tag the existing r-code without the must recompile.

See OpenEdge Data Management: Database Administration for more information on using the DBAUTHKEY and RCODEKEY features of PROUTIL.

Use the agent’s production setting

For production environments, either Internet or intranet, you should set the agent application mode to Production. You set this option through the Progress Explorer in the Properties dialog box, as shown in Figure 4–9. After setting this, you should stop and start the WebSpeed service to activate the change.

Figure 4–9: Setting Production mode for WebSpeed agents

Modifying web-disp.p

By default, the agents run web/objects/web-disp.p as their startup program. Each request that is issued to an agent runs through this code. This is the best place to control what happens to each request.

Modify web-disp.p to:

Because each request must go through this code, any changes made to web-disp.p are system wide.

If you want to change this code, you should move it into your application’s source tree and rename it. This way, when a service pack installs a newer version of web-disp.p, your changes are not overwritten. You should also compare your code with the new code shipped in the service pack to make sure you also incorporate any bug fixes or enhancements.

Example 4–1 shows a simplified version of the default WebSpeed web-disp.p.

Example 4–1: Default web-disp.p  
/* Set the web-request trigger. */ 
ON "WEB-NOTIFY":U ANYWHERE DO: 
  OUTPUT {&WEBSTREAM} TO "WEB":U. 
  /* Parse the request/CGI from the web server. */ 
  RUN init-cgi     IN web-utilities-hdl. 
  /* Initialize for web-request. */ 
  RUN init-request IN web-utilities-hdl. 
  AppProgram = (IF AppProgram = "debug":U THEN "webutil/debug.p":U ELSE 
               (IF AppProgram = "ping":U  THEN "webutil/ping.p":U  ELSE 
               (IF AppProgram = "reset":U THEN "webutil/reset.p":U ELSE 
                AppProgram))). 
  RUN run-web-object IN web-utilities-hdl (AppProgram) NO-ERROR.  
  /* Run clean up and maintenance code */ 
  RUN end-request IN web-utilities-hdl NO-ERROR. 
  /* Output any pending messages queued up by queue-message() */ 
  IF available-messages(?) THEN 
    output-messages("all", ?, "Messages:"). 
  OUTPUT {&WEBSTREAM} CLOSE. 
END. /* ON "WEB-NOTIFY" */ 
/* Wait for a web-request to come in */ 
WAIT-FOR-BLOCK:  
REPEAT ON ERROR UNDO WAIT-FOR-BLOCK, LEAVE WAIT-FOR-BLOCK  
       ON QUIT  UNDO WAIT-FOR-BLOCK, LEAVE WAIT-FOR-BLOCK 
       ON STOP  UNDO WAIT-FOR-BLOCK, NEXT  WAIT-FOR-BLOCK:  
  WAIT-FOR "WEB-NOTIFY":U OF DEFAULT-WINDOW.  
END. /* WAIT-FOR-BLOCK: REPEAT... */ 

Note: Example 4–1 code will not run. Much of the code has been removed. The purpose of this example is to show program flow.

Example 4–2 shows a simplified, secure web-disp.p. Again, this code will not run; you would must insert the bold text into the original web-disp.p replacing the “AppProgram = ...” code.

This code stops PING, DEBUG, and RESET, changes the extension of any requested program into r-code, checks that the r-code file exists, and verifies if this r-code is valid for this user by looking up a database table called UserPrograms. You must create a table called UserPrograms containing (at least) both these fields. Also, UserID is a variable that you must instantiate.

You would usually use a cookie, hidden fields, or URL parameters to hold the user’s ID. This should be encrypted in a suitable manner. See the "Parameter passing" section for an example of encrypting this ID.

Example 4–2: Secure web-disp.p  
/* Set the web-request trigger. */ 
ON "WEB-NOTIFY":U ANYWHERE DO: 
  DEFINE VARIABLE vLocn AS INTEGER NO-UNDO. 
  OUTPUT {&WEBSTREAM} TO "WEB":U. 
  /* Parse the request/CGI from the web server. */ 
  RUN init-cgi     IN web-utilities-hdl. 
  /* Initialize for web-request. */ 
  RUN init-request IN web-utilities-hdl. 
  /* Remove current extension */  
  vLocn = R-INDEX (AppProgram, ".").  
  IF vLocn > 0  
  THEN  
    AppProgram = SUBSTR (AppProgram, 1, vLocn - 1). 
  /* Add a .R */ 
  AppProgram = AppProgram + ".r". 
  /* Can this User run this program OR does it exist? */ 
  IF NOT CAN-FIND (UserPrograms WHERE UserPrograms.UserID  = UserID 
                                  AND UserPrograms.Program = AppProgram) 
    OR 
    SEARCH (AppProgram) = ? 
  THEN 
    AppProgram = "NotValidProgram.r". 
RUN run-web-object IN web-utilities-hdl (AppProgram) NO-ERROR.  
   
  /* Run clean up and maintenance code */ 
  RUN end-request IN web-utilities-hdl NO-ERROR. 
   
  /* Output any pending messages queued up by queue-message() */ 
  IF available-messages(?) THEN 
    output-messages("all", ?, "Messages:"). 
     
  OUTPUT {&WEBSTREAM} CLOSE. 
END. /* ON "WEB-NOTIFY" */ 

After you have created your new-web-disp.p, you must change the agent parameters to reference it, as shown in Figure 4–10.

Figure 4–10: Changing agent parameters to reference new-web-disp.p

Minimize the PROPATH

It is essential that the PROPATH is kept to a minimum, both for performance and security. The OpenEdge-install/tty directory and all the r-code libraries (*.PL) in the OpenEdge-install/tty directory are added to the end of your PROPATH setting by default. This means that there are many programs in your PROPATH that you did not write and anyone can run these programs by adding them to the end of your URL.

To avoid this, simply rename the OpenEdge-install/tty directory to OpenEdge-install/tty_save. Then, copy all the r-code files you use to a new directory called tty in your deployment area and add this to the end of your PROPATH. Remember that some of the r-code files WebSpeed might use are in the .PL files, and you must extract them using the PROLIB utility documented in OpenEdge Deployment: Managing 4GL Applications .

Parameter passing

If you want to pass parameters between Web requests, you can use hidden fields on forms, URL parameters, cookies, or a combination of each technique. Each technique has pros and cons. Hidden fields only work on forms, URL parameters are visible to the end user, and cookies are not allowed by some users.

The simplest way to pass many parameters between Web requests is to use the database. You pass a unique identifier for each user or session between requests, and use this as a key into a “state” table held in the database. This technique requires that only a small token be passed between requests, as the majority of the data is safe and secure in the database.

Do not pass the unique identifier in plain text. Doing so makes it very easy for an end user to change the value (even in hidden fields or cookies) and become someone else. Use code, similar to the code shown in Example 4–3, to prevent people from changing the unique identifier, unless they know the hidden words, in this case “Web” and “Speed.”

Example 4–3: Passing unique identifiers  
/* 
** This code assumes that the Unique ID will not contain 
** any colons (:). 
*/ 
DEFINE VARIABLE vToken    AS CHAR NO-UNDO. 
DEFINE VARIABLE vUniqueID AS CHAR NO-UNDO. 
/* WebEncode function */ 
FUNCTION WebEncode RETURNS CHAR (pUniqueID AS CHAR): 
  RETURN pUniqueID + ":" + ENCODE ("Web" + pUniqueID + "Speed"). 
END. 
---- Use this to encode the Unique ID, then pass as parameter ---- 
/* Encode Unique ID */ 
vToken = WebEncode (vUniqueID). 
---- Use this to decode the token passed as a parameter ---- 
/* Decode and check Token */ 
vUniqueID = ENTRY (1, vToken, ":"). 
IF vToken = WebEncode (vUniqueID) 
THEN 
  /* vToken has not been modified */ 
ELSE 
  /* ERROR - vToken has been modified */ 


Copyright © 2005 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095